﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text.RegularExpressions;
using System.Xml;
using Unis.Framework.Core.Exceptions;
using Unis.Framework.Core.Log;
using Unis.Framework.Core.Utility;
using Unis.Framework.ORM.BaseDefiniens.Enums;
using Unis.Framework.ORM.Common;
using Unis.Framework.ORM.DbSql;
using Unis.Framework.ORM.Exceptions;
using Unis.Framework.ORM.Mapping;
using Unis.ORM.Common;
using Unis.ORM.DbSql;
using Unis.ORM.Mapping;

namespace Unis.Framework.ORM.Xml
{
    public sealed class SqlConfigHelper
    {
        // Fields
        private static SqlConfigHelper _Instance;
        private static object _Obj = new object();
        private const int DEFAULT_PARAM_LENGTH = 0x80;
        private static readonly string SQL_PARAMS_PATH = "Entity/Sqls/Sql";
        private static string[] SQL_SPEC_STRING = SqlShareHelper.SQL_SPEC_STRING;
        public static string XML_FILE_PATH = null;
        private static readonly string XML_PARAM_MAPPINGS = "QueryParamMappings";
        private static readonly string XML_SQL_STRING_NAME = "SqlString";
        private static readonly string XML_SQL_STRING_TEXT_NAME = "String";

        // Methods
        public SqlConfigHelper()
        {
            XML_FILE_PATH =CommonHelper.GetApplicationDirectory();
            XML_FILE_PATH = XML_FILE_PATH + ConfigurationManager.GetAppSetting("SqlXmlConfigPath");
        }

        private XmlDocument createXmlDocument(string xmlFileName)
        {
            return new XmlResourceHelper().CreateXmlDocument(XML_FILE_PATH, xmlFileName);
        }

        private string formatSqlString(string strSql)
        {
            if (string.IsNullOrEmpty(strSql))
            {
                return string.Empty;
            }
            string input = strSql;
            return Regex.Replace(Regex.Replace(Regex.Replace(input, @"[\r\n]+", " ", RegexOptions.IgnoreCase), @"[\t]+", " ", RegexOptions.IgnoreCase), "[ ]+", " ", RegexOptions.IgnoreCase).Replace("@", SqlShareHelper.SQL_XML_CFG_PARAM_PREFIX).Replace(":", SqlShareHelper.SQL_XML_CFG_PARAM_PREFIX);
        }

        private string getNodeAttValue(XmlNode xmlNode, string attName)
        {
            if (xmlNode.Attributes[attName] == null)
            {
                return string.Empty;
            }
            return xmlNode.Attributes[attName].Value.ToString();
        }

        public Dictionary<OperationType, SqlString[]> GetObjectStandardEditSql(string xmlFileName, OperationType optTypes)
        {
            Dictionary<OperationType, SqlString[]> dictionary = new Dictionary<OperationType, SqlString[]>();
            if ((optTypes & OperationType.Insert) != OperationType.None)
            {
                SqlString[] sqlString = this.GetSqlString(xmlFileName, "AddObject");
                if ((sqlString == null) || (sqlString.Length == 0))
                {
                    throw new XmlSqlConfigNotExistsException(xmlFileName, "AddObject");
                }
                dictionary[OperationType.Insert] = sqlString;
            }
            if ((optTypes & OperationType.Update) != OperationType.None)
            {
                SqlString[] strArray2 = this.GetSqlString(xmlFileName, "UpdateObject");
                if ((strArray2 == null) || (strArray2.Length == 0))
                {
                    throw new XmlSqlConfigNotExistsException(xmlFileName, "UpdateObject");
                }
                dictionary[OperationType.Update] = strArray2;
            }
            if ((optTypes & OperationType.DeleteNotIn) != OperationType.None)
            {
                SqlString[] strArray3 = this.GetSqlString(xmlFileName, "DeleteNotInIDS");
                if ((strArray3 == null) || (strArray3.Length == 0))
                {
                    throw new XmlSqlConfigNotExistsException(xmlFileName, "DeleteNotInIDS");
                }
                dictionary[OperationType.DeleteNotIn] = strArray3;
            }
            return dictionary;
        }

        private XmlNode getSqlNode(string xmlFileName, string sqlName)
        {
            foreach (XmlNode node in this.createXmlDocument(xmlFileName).SelectNodes(SQL_PARAMS_PATH))
            {
                if (((node.NodeType == XmlNodeType.Element) && (node.Attributes["Name"] != null)) && (string.Compare(node.Attributes["Name"].Value.ToString(), sqlName, true) == 0))
                {
                    return node;
                }
            }
            return null;
        }

        private List<SqlParamInfo> getSqlParams(XmlNode sqlNode)
        {
            List<SqlParamInfo> list = new List<SqlParamInfo>();
            if ((sqlNode != null) && (sqlNode.ChildNodes.Count != 0))
            {
                foreach (XmlNode node in sqlNode.ChildNodes)
                {
                    if ((node.NodeType != XmlNodeType.Element) || (string.Compare(node.Name, "Param", true) != 0))
                    {
                        continue;
                    }
                    SqlParamInfo item = new SqlParamInfo();
                    string str = this.getNodeAttValue(node, "Name");
                    str = SqlShareHelper.SQL_XML_CFG_PARAM_PREFIX + str.Substring(1, str.Length - 1);
                    item.Name = str;
                    string str2 = this.getNodeAttValue(node, "Column");
                    if (!string.IsNullOrEmpty(str2))
                    {
                        item.MappingName = str2;
                    }
                    string str3 = this.getNodeAttValue(node, "Description");
                    if (string.IsNullOrEmpty(str3))
                    {
                        item.Description = item.Name;
                    }
                    else
                    {
                        item.Description = str3;
                    }
                    string str4 = this.getNodeAttValue(node, "TypeName");
                    if (string.IsNullOrEmpty(str4))
                    {
                        item.DbType = DbShare.Instance.SystemTypeNameToDbType("System.String");
                    }
                    else
                    {
                        item.DbType = DbShare.Instance.SystemTypeNameToDbType(str4);
                    }
                    string str5 = this.getNodeAttValue(node, "Length");
                    if (string.IsNullOrEmpty(str5))
                    {
                        item.Length = 0x80;
                    }
                    else
                    {
                        item.Length = Convert.ToInt32(str5);//   DataConvertManager.ToInt(str5);
                    }
                    string str6 = this.getNodeAttValue(node, "Overcast");
                    if (!string.IsNullOrEmpty(str6))
                    {
                        item.Overcast = Convert.ToBoolean(str6);//  DataConvertManager.ToBool(str6);
                    }
                    string str7 = this.getNodeAttValue(node, "Direction");
                    if (string.IsNullOrEmpty(str7))
                    {
                        item.Direction = ParameterDirection.Input;
                    }
                    else
                    {
                        item.Direction = (ParameterDirection)Enum.Parse(typeof(ParameterDirection), str7);
                    }
                    if (SqlShareHelper.HS_SQL_SPEC_STRING.ContainsKey(str.ToUpper()))
                    {
                        item.Overcast = true;
                    }
                    list.Add(item);
                }
            }
            return list;
        }

        public QueryParameterMappings GetSqlQueryParamMappings(string xmlFileName, string sqlName)
        {
            XmlNode node = this.getSqlNode(xmlFileName, sqlName);
            if ((node == null) || (node.ChildNodes.Count == 0))
            {
                TraceEx.Write("在XML 文件：" + xmlFileName + " 中获取相应SQL 语句：" + sqlName + "出错，请检查资源文件或者对应SQL 语句是否存在！");
                return null;
            }
            QueryParameterMappings mappings = null;
            foreach (XmlNode node2 in node.ChildNodes)
            {
                if ((node2.NodeType == XmlNodeType.Element) && (string.Compare(node2.Name, XML_PARAM_MAPPINGS, true) == 0))
                {
                    mappings = new QueryParameterMappings();
                    if (node2.Attributes["DefaultTableAlias"] != null)
                    {
                        mappings.DefaultTableAlias = node2.Attributes["DefaultTableAlias"].Value;
                    }
                    foreach (XmlNode node3 in node2.ChildNodes)
                    {
                        if ((node3.NodeType != XmlNodeType.Element) || (string.Compare(node3.Name, "Mapping", true) != 0))
                        {
                            continue;
                        }
                        if ((node3.Attributes["Name"] == null) || (node3.Attributes["DbFieldName"] == null))
                        {
                            throw new APPException(string.Format("XML配置文件{0},配置QueryParamMappings 是可能没有配置 Name 或者 DbFieldName!", xmlFileName));
                        }
                        mappings.Add(new QueryParameterMappingInfo(node3.Attributes["Name"].Value, node3.Attributes["DbFieldName"].Value));
                    }
                    return mappings;
                }
            }
            return mappings;
        }

        public SqlString[] GetSqlString(string xmlFileName, string sqlName)
        {
            XmlNode node = this.getSqlNode(xmlFileName, sqlName);
            if ((node == null) || (node.ChildNodes.Count == 0))
            {
                TraceEx.Write("在XML 文件：" + xmlFileName + " 中获取相应SQL 语句：" + sqlName + "出错，请检查资源文件或者对应SQL 语句是否存在！");
                return null;
            }
            List<SqlString> list = new List<SqlString>();
            foreach (XmlNode node2 in node.ChildNodes)
            {
                if ((node2.NodeType != XmlNodeType.Element) || (string.Compare(node2.Name, XML_SQL_STRING_NAME, true) != 0))
                {
                    continue;
                }
                string strSql = string.Empty;
                foreach (XmlNode node3 in node2.ChildNodes)
                {
                    if ((node3.NodeType == XmlNodeType.Element) && (string.Compare(node3.Name, XML_SQL_STRING_TEXT_NAME, true) == 0))
                    {
                        TraceEx.Write("成功发现SQL 语句：" + sqlName);
                        strSql = this.formatSqlString(node3.InnerText.Trim());
                        break;
                    }
                }
                List<SqlParamInfo> paramField = this.getSqlParams(node2);
                SqlString item = new SqlString(strSql, paramField);
                list.Add(item);
            }
            return list.ToArray();
        }

        // Properties
        public static SqlConfigHelper Instance
        {
            get
            {
                if (_Instance == null)
                {
                    lock (_Obj)
                    {
                        if (_Instance == null)
                        {
                            _Instance = new SqlConfigHelper();
                        }
                    }
                }
                return _Instance;
            }
        }
    }
}
